package cubacn

import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils

import java.nio.file.Paths
import java.text.DateFormat
import java.text.SimpleDateFormat

class BaiduSubmitter {
    static String siteMapUrl
    static String baiduToken
    static String siteUrl
    static long startTime = (new Date()).time
    private static HashMap<String, Long> history = [:]
    private static HashMap<String, Long> urls = [:]
    private static DateFormat format = new SimpleDateFormat("yyyyMMddHH:mm:ss", Locale.CHINA)

    private static long parseTimeString(String dateStr) {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.CHINA)
        format.setTimeZone(TimeZone.getTimeZone("UTC"))
        Date date = format.parse(dateStr)
        Long l = date.getTime()
        Date d1 = new Date(l + 1000l)
        d1.time
    }

    private static void loadUrlFromSiteMap() {
        urls = new HashMap<String, Long>()
        def parser = new XmlParser()
        Node node = parser.parse(siteMapUrl)
        node.children().each {
            urlNode ->
                def pageUrl = urlNode.loc[0].text() as String
                def lastmod = urlNode.lastmod[0].text() as String
                def timestamp = parseTimeString(lastmod)
                urls.put(pageUrl, timestamp)
        }
    }

    private static Properties loadProperites() {
        Properties properties = new Properties()
        propertiesFile.withInputStream {
            properties.load(it)
        }
        properties
    }

    private static File getDataDir() {
        Paths.get(rootPath, "data").toFile()
    }

    private static File getHistoryFile() {
        Paths.get(dataDir.path, "baiduPushHistory.json").toFile()
    }

    private static File getPropertiesFile() {
        Paths.get(rootPath, "baidupush.properties").toFile()
    }

    private static String getRootPath() {
        File file = new File(BaiduSubmitter.getProtectionDomain().getCodeSource().getLocation().getPath())
        if (file.isFile()) {
            return file.parentFile.path
        }
        def path = new File(BaiduSubmitter.classLoader.getResource("baidupush.properties").path.substring(1)).parentFile.path
        path
    }

    private static void loadPushHistory() {
        history = new HashMap<String, Long>()
        def jsonSlurper = new JsonSlurper()
        if (historyFile.exists()) {
            history = jsonSlurper.parse(historyFile) as HashMap<String, Long>
        }
    }

    private static void loadProperties() {
        def properties = loadProperites()
        baiduToken = properties.get("token")
        siteMapUrl = properties.get("siteMap")
        siteUrl = properties.get("siteUrl")
    }

    static void doPush() {
        DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA)
        def logFileName = format.format(new Date()) + ".log"
        def created = new ArrayList<String>(), updated = new ArrayList<String>()
        urls.each {
            if (!history.containsKey(it.key)) {
                created.add(it.key)
            } else {
                def timstap = history.get(it.key)
                if (it.value > timstap) {
                    updated.add(it.key)
                }
            }
        }
        String updateResult = "", createResult = ""
        try {
            if (updated.size() > 0) {
                def updatedR = postUpdated(updated)
                def success = updatedR.get("success") as Integer
                def invalidUrls = updatedR.get("not_valid") as List<String>
                if(!invalidUrls){
                    invalidUrls=new ArrayList<String>()
                }
                def invalidUrlsSet=invalidUrls.toSet()
                updateResult = JsonOutput.toJson(updatedR)
                updated.each {
                    if(!invalidUrlsSet.contains(it)){
                        history.put(it, startTime)
                    }
                }
            }
        } catch (Exception ex) {
            updateResult = "失败:" + ex.message
        }

        try {
            if (created.size() > 0) {
                def createdR = postCreated(created)
                def success = createdR.get("success") as Integer
                def invalidUrls = createdR.get("not_valid") as List<String>
                if(!invalidUrls){
                    invalidUrls=new ArrayList<String>()
                }
                def invalidUrlsSet=invalidUrls.toSet()
                createResult = JsonOutput.toJson(createdR)
                created.each {
                    if(!invalidUrlsSet.contains(it)){
                        history.put(it, startTime)
                    }
                }
            }

        } catch (Exception ex) {
            createResult = "失败:" + ex.message
        }
        def logContext =
                "更新数量:${updated.size()} \r " +
                        "更新结果: \r " +
                        " ${updateResult} \r " +
                        "提交数量:${created.size()} \r " +
                        "提交结果: \r " +
                        " ${createResult} \r "

        def logFile = Paths.get(dataDir.path, logFileName).toFile()
        logFile.write(logContext, "UTF-8")
        historyFile.write(JsonOutput.toJson(history), "UTF-8")
    }

    private static void checkDataDir() {
        if(!dataDir.exists()){
            dataDir.mkdirs()
        }
    }
    /**
     * @param list
     * @return
     */
    static Map postUpdated(List list) {
        def url = "http://data.zz.baidu.com/update?site=${siteUrl}&token=${baiduToken}"
        executePost(url, list)
    }
    /**
     * @param list
     * @return
     */
    static Map postCreated(List list) {
        def url = "http://data.zz.baidu.com/urls?site=${siteUrl}&token=${baiduToken}"
        executePost(url, list)
    }

    static Map executePost(String postUrl, List<String> Datalist) {
        String rawData = Datalist.join("\n")
        def httpClient = HttpClients.createDefault()
        HttpPost httpPost = new HttpPost(postUrl)
        httpPost.setHeader("Content-Type", "text/plain")
        StringEntity entity = new StringEntity(rawData)
        httpPost.setEntity(entity)
        String responseMsg = ""
        try {
            def response = httpClient.execute(httpPost)
            def responseText = EntityUtils.toString(response.getEntity(), "UTF-8")
            def statusCode = response.getStatusLine().getStatusCode()
            if (200 != statusCode) {
                throw new Exception("request failed, statusCode :${statusCode}")
            }
            JsonSlurper jsonSlurper = new JsonSlurper()
            return jsonSlurper.parseText(responseText) as Map
        } finally {
            httpPost.releaseConnection()
            httpClient.close()
        }
    }

    static void main(String[] args) {
        try{
            run()
        }catch(Exception ex){
            def logFile=new File(dataDir,"error.log")
            logFile.write(ex.getStackTrace().toString())
        }

    }
    static void run() {
        checkDataDir()
        loadProperties()
        loadUrlFromSiteMap()
        loadPushHistory()
        doPush()
    }
}
